/**
 * 
 */
package edu.cmu.mism.dgjava.graphs;

import org.eclipse.birt.chart.api.ChartEngine;
import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.factory.GeneratedChartState;
import org.eclipse.birt.chart.factory.Generator;
import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.LineStyle;
import org.eclipse.birt.chart.model.attribute.Position;
import org.eclipse.birt.chart.model.attribute.TickStyle;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
import org.eclipse.birt.chart.model.data.NumberDataSet;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl;
import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;
import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.layout.Plot;
import org.eclipse.birt.chart.model.type.LineSeries;
import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;
import org.eclipse.birt.core.framework.PlatformConfig;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

/**
 * 
 * The Chart diagram that draws the statisics results for option calculation
 * 
 * @author Christian
 * 
 */
public class DGChartDiagram extends Canvas implements PaintListener {

	// device render
	private IDeviceRenderer render;
	// cached image to draw the canvas
	private Image cachedImage;
	private GeneratedChartState state;
	// chat instance
	private ChartWithAxes chart;

	public DGChartDiagram(Composite parent, int style) {
		super(parent, style);

		// initialize the SWT rendering device
		try {
			PlatformConfig pf = new PlatformConfig();
			render = ChartEngine.instance(pf).getRenderer("dv.SWT");//$NON-NLS-1$

		} catch (ChartException pex) {
			pex.printStackTrace();
		}

		createDGChart();
		addPaintListener(this);
	}

	/**
	 * @param size
	 */
	public void drawToCachedImage(Rectangle size) {
		GC gc = null;
		try {
			if (cachedImage != null)
				cachedImage.dispose();
			cachedImage = new Image(Display.getCurrent(), size);

			gc = new GC(cachedImage);
			render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gc);

			Generator gr = Generator.instance();
			gr.render(render, state);
		} catch (ChartException ex) {
			ex.printStackTrace();

		} finally {
			if (gc != null)
				gc.dispose();
		}
	}

	/**
	 * @return
	 */
	private void createDGChart() {
		chart = ChartWithAxesImpl.create();

		// Plot
		chart.getBlock().setBackground(ColorDefinitionImpl.WHITE());
		Plot p = chart.getPlot();
		p.getClientArea().setBackground(
				ColorDefinitionImpl.create(255, 255, 225));

		// Legend
		Legend lg = chart.getLegend();
		lg.setVisible(false);
		// LineAttributes lia = lg.getOutline();
		// lg.getText().getFont().setSize(10);
		// lia.setStyle(LineStyle.SOLID_LITERAL);

		// Title
		chart.getTitle().getLabel().getCaption().setValue(
				"Option Calculation Statistics Chart");//$NON-NLS-1$
		chart.getTitle().getLabel().getCaption().getFont().setSize(13);

		// X-Axis
		Axis xAxisPrimary = (chart).getPrimaryBaseAxes()[0];
		xAxisPrimary.getLabel().getCaption().setValue("X Axis");//$NON-NLS-1$
		// xAxisPrimary.getLabel().getCaption().getFont().setRotation(37);
		xAxisPrimary.getLabel().getCaption().getFont().setSize(10);
		xAxisPrimary.setLabelPosition(Position.BELOW_LITERAL);
		xAxisPrimary.setTitlePosition(Position.BELOW_LITERAL);
		xAxisPrimary.getTitle().getCaption().getFont().setSize(10);
		xAxisPrimary.getTitle().setVisible(true);

		xAxisPrimary.setType(AxisType.LINEAR_LITERAL);

		xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL);
		xAxisPrimary.getMajorGrid().getLineAttributes().setStyle(
				LineStyle.DOTTED_LITERAL);
		xAxisPrimary.getMajorGrid().getLineAttributes().setColor(
				ColorDefinitionImpl.RED());
		xAxisPrimary.getMajorGrid().getLineAttributes().setVisible(true);

		// Y-Axis
		Axis yAxisPrimary = (chart).getPrimaryOrthogonalAxis(xAxisPrimary);
		yAxisPrimary.getLabel().getCaption().setValue("Y Axis");//$NON-NLS-1$
		// yAxisPrimary.getLabel().getCaption().getFont().setRotation(37);
		yAxisPrimary.getLabel().getCaption().getFont().setSize(10);

		yAxisPrimary.setLabelPosition(Position.LEFT_LITERAL);

		yAxisPrimary.setTitlePosition(Position.LEFT_LITERAL);
		yAxisPrimary.getTitle().getCaption().getFont().setSize(10);
		yAxisPrimary.getTitle().setVisible(true);

		yAxisPrimary.setType(AxisType.LINEAR_LITERAL);

		yAxisPrimary.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL);
		yAxisPrimary.getMajorGrid().getLineAttributes().setStyle(
				LineStyle.DOTTED_LITERAL);
		yAxisPrimary.getMajorGrid().getLineAttributes().setColor(
				ColorDefinitionImpl.RED());
		yAxisPrimary.getMajorGrid().getLineAttributes().setVisible(true);

		// X-Series
		// createLineSeriesDefinition(xAxisPrimary, "x series");
		Series seX = SeriesImpl.create();
		SeriesDefinition sdX = SeriesDefinitionImpl.create();
		xAxisPrimary.getSeriesDefinitions().add(sdX);
		sdX.getSeries().add(seX);

		// Adding Y-Series
		createLineSeriesDefinition(yAxisPrimary, "y series");

		// Update data
		// TODO for testing purpose
		updateDataSet(da1, da2, "Asset Price", "Option Price");

	}

	/**
	 * 
	 * @param ax
	 * @param identifier
	 */
	private void createLineSeriesDefinition(Axis ax, String identifier) {
		LineSeries ls = (LineSeries) LineSeriesImpl.create();
		ls.setSeriesIdentifier(identifier);
		ls.setConnectMissingValue(true);
		ls.getLineAttributes().setColor(ColorDefinitionImpl.GREEN());
		// no marker for data points
		ls.getMarkers().clear();
		// for (int i = 0; i < ls.getMarkers().size(); i++) {
		// ((Marker) ls.getMarkers().get(i)).setType(MarkerType.BOX_LITERAL);
		// }
		ls.setCurve(true);

		SeriesDefinition sd = null;
		if (ax.getSeriesDefinitions().size() == 0) {
			sd = SeriesDefinitionImpl.create();
			ax.getSeriesDefinitions().add(sd);
		} else {
			sd = ax.getSeriesDefinitions().get(0);
		}

		sd.getSeries().add(ls);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events
	 * .PaintEvent)
	 */
	public void paintControl(PaintEvent e) {
		// create new cached image
		Rectangle d = this.getClientArea();
		Image imgChart = new Image(this.getDisplay(), d);
		GC gcImage = new GC(imgChart);

		render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gcImage);

		Bounds bo = BoundsImpl.create(0, 0, d.width, d.height);
		bo.scale(72d / render.getDisplayServer().getDpiResolution());

		Generator gr = Generator.instance();
		try {
			// paint the canvas by calling the generator of the BIRT chart
			// engine
			state = gr.build(render.getDisplayServer(), chart, bo, null, null,
					null);
			gr.render(render, state);
			GC gc = e.gc;
			gc.drawImage(imgChart, d.x, d.y);

		} catch (ChartException ce) {
			ce.printStackTrace();
		}
	}

	/**
	 * Refresh the dataSet for this line chart by giving the x-y coordinate
	 * values.
	 * 
	 * @param xValues
	 *            data set for x values
	 * @param vValues
	 *            data set for y values corresponding to the x values at the
	 *            same array index
	 * @param xLable
	 *            new label for x axis
	 * @param yLable
	 *            new label for y axis
	 */
	public void updateDataSet(double[] xValues, double[] vValues,
			String xLable, String yLable) {
		// Associate with Data Set
		NumberDataSet seriesXValues = NumberDataSetImpl.create(xValues);
		NumberDataSet seriesYValues = NumberDataSetImpl.create(vValues);

		// X-Axis
		Axis xAxisPrimary = chart.getPrimaryBaseAxes()[0];
		// Update label
		xAxisPrimary.getTitle().getCaption().setValue(xLable);

		SeriesDefinition sdX = xAxisPrimary.getSeriesDefinitions().get(0);
		(sdX.getSeries().get(0)).setDataSet(seriesXValues);

		// Y-Axis
		Axis yAxisPrimary = chart.getPrimaryOrthogonalAxis(xAxisPrimary);
		yAxisPrimary.getTitle().getCaption().setValue(yLable);

		SeriesDefinition sdY = yAxisPrimary.getSeriesDefinitions().get(0);
		(sdY.getSeries().get(0)).setDataSet(seriesYValues);
	}

	// Test Date Set
	private static final double[] da1 = { 10, 20, 30, 40, 50, 60, 70, 80, 90,
			100 };

	private static final double[] da2 = { 10, 32.95, 48.5, 80, 79, 65, 57, 37,
			20, 7.9 };

}
